/*
 * Copyright (c) zhg2yqq.com Corp.
 * All Rights Reserved.
 */
package com.zhg2yqq.wheels.mvc.base;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.TypeUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zhg2yqq.wheels.common.exception.BusinessException;
import com.zhg2yqq.wheels.common.response.BaseResponseCode;
import com.zhg2yqq.wheels.mvc.MybatisEncryptProperties;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author zhg2yqq, 2022年12月3日
 * @version zhg2yqq v1.0
 */
public abstract class BaseController<T, V, S extends IBaseService<T>> {
    @Autowired
    private MybatisEncryptProperties encryptProperties;
    private AtomicReference<Class<T>> entityClass = new AtomicReference<>();
    private AtomicReference<Class<V>> voClass = new AtomicReference<>();
    private AtomicReference<S> service = new AtomicReference<>();

    @SuppressWarnings("unchecked")
    protected Class<V> getVOClass() {
        if (voClass.get() == null) {
            voClass.compareAndSet(null, (Class<V>) getClass(1));
        }
        return voClass.get();
    }

    @SuppressWarnings("unchecked")
    protected Class<T> getEntityClass() {
        if (entityClass.get() == null) {
            entityClass.compareAndSet(null, (Class<T>) getClass(0));
        }
        return entityClass.get();
    }

    @SuppressWarnings("unchecked")
    protected Class<Object> getClass(int idx) {
        Type entityType = TypeUtil.getTypeArgument(this.getClass(), idx);
        if (entityType instanceof ParameterizedType) {
            ParameterizedType type = (ParameterizedType) entityType;
            return (Class<Object>) type.getRawType();
        }
        return (Class<Object>) entityType;
    }

    public IPage<V> page(BasePageCondition<T> condition) {
        return getService().page(condition.getPage(), condition.getQueryWrapper())
                .convert(source -> transfer(source, getVOClass()));
    }

    public List<V> list(BaseCondition<T> condition) {
        return getService().list(condition.getQueryWrapper()).stream()
                .map(source -> transfer(source, getVOClass())).collect(Collectors.toList());
    }

    public boolean remove(String id) {
        return getService().removeById(id);
    }

    public boolean removeBatchs(List<String> ids) {
        if (ids.isEmpty()) {
            return false;
        }
        return getService().removeBatchByIds(ids);
    }

    /**
     * 类型转化
     *
     * @param <O>         转化目标类型
     * @param source      源
     * @param targetClass 目标类型
     * @return 目标
     */
    protected <O> O transfer(Object source, Class<O> targetClass) {
        return BeanUtil.copyProperties(source, targetClass);
    }

    protected <O> List<O> transferList(List<?> sources, Class<O> targetClass) {
        return BeanUtil.copyToList(sources, targetClass);
    }

    protected <O> O validEntityNotNull(O object) {
        return Optional.ofNullable(object)
                .orElseThrow(() -> BusinessException.of(BaseResponseCode.RESOURCE_NOT_EXISTS));
    }

    protected MybatisEncryptProperties getEncryptProperties() {
        return encryptProperties;
    }

    @SuppressWarnings("unchecked")
    public S getService() {
        if (service.get() == null) {
            service.compareAndSet(null, (S) SpringUtil.getBean(getClass(2)));
        }
        return service.get();
    }
}
